package core.manager
{
import com.adobe.serialization.json.JSON;
import com.greensock.TweenMax;
import com.greensock.easing.Back;
import com.greensock.easing.Bounce;
import com.greensock.easing.Circ;
import com.greensock.easing.Cubic;
import com.greensock.easing.Elastic;
import com.greensock.easing.Expo;
import com.greensock.easing.Linear;
import com.greensock.easing.Quad;
import com.greensock.easing.Quart;
import com.greensock.easing.Quint;

import core.Configuration;
import core.StageProxy;

import flash.display.DisplayObject;
import flash.filters.BitmapFilter;
import flash.geom.Point;
import flash.utils.getDefinitionByName;

import fliso.IsoSprite;
import fliso.utils.game.WorldPosition;

import framework.core.AssetsManager;
import framework.view.components.graphics.Asset;
import framework.view.components.graphics.SWF;

import isoengine.IsoEngineProxy;
import isoengine.drop.DropItem;
import isoengine.effects.BubbleEffect;
import isoengine.effects.EffectObjectBase;

import utils.DropUtil;

import values.effects.EffectSettingValue;

public class EffectManager
{
	private static var dropAnimationDef:*;
	private static var collectAnimationDef:*;
	private static var collectFadeOutAnimationDef:*;
	
	public static function initialize():void
	{
		//Include easing defination
		Expo
		Elastic
		Quad
		Quart
		Quint
		Back
		Cubic
		Circ
		Linear
		Elastic
		Bounce
		
		//Init effect defination		
		var dropEffect:* = getDefinationsByKey("drop");
		dropAnimationDef = dropEffect.defination.(@key == "dropAnimation");
        DropManager.dropDelay = dropAnimationDef.delay.@value;
        
		collectAnimationDef = dropEffect.defination.(@key == "collectAnimation");
		collectFadeOutAnimationDef = dropEffect.defination.(@key == "collectFadeOutAnimation");
		
		minAutoCollectTimeout = Number(dropEffect.defination.(@key == "autoCollect").timeout.@min);
		maxAutoCollectTimeout = Number(dropEffect.defination.(@key == "autoCollect").timeout.@max);
	}
	
	public static function getDefinationsByKey(key:String):*
	{
		return EffectSettingValue.getByKey(key).defination;
	}
	
	public static function createFilter(data:XML):BitmapFilter
	{
		var ref:Class = getDefinitionByName(data.@classRef) as Class;
		var filter:BitmapFilter = new ref();
		for (var key:String in data.attributes())
		{
			var propName:String = String(XMLList(data.attributes()[key]).name());
			if (propName != "classRef")
			{
				filter[propName] = data.attributes()[key];
			}
		}
		return filter;
	}
	
	public static function applyEffect(target:IsoSprite, effect:*):void
	{
		var clearCommand:* = effect.command.(@type == "clearFilter");
		if (String(clearCommand.@type) != "")
		{
			target.filters = [];
		}
		var filters:Array;
		for each (var filterData:* in effect.filter)
		{
			if (!filters) filters = [];
			filters.push(createFilter(filterData));
		}
		if(filters)
		{
			target.filters = filters;
		}
	}
    
    public static function createGlobalEffect(key:String, param:*, ref:Class = null):EffectObjectBase
    {
        if (!ref)
        {
            ref = EffectObjectBase;
        }
        var obj:EffectObjectBase = new ref();
       
        var def:* = getDefinationsByKey("global_effects").defination.(@key == key);
        
        var classRef:String = JSON.decode(String(def.lib))[param];
        
        var loadedHandler:Function = function (asset:Asset):void
        {
            obj.initBySWF(asset as SWF, classRef);
        }
        
        AssetsManager.loadAsset(Configuration.assetsPath + String(def.asset.@url), loadedHandler, null, String(def.asset.@mode));        
        
        return obj;
    }
    
    public static function createBubbleEffect(size:int, position:WorldPosition):EffectObjectBase
    {
        var obj:EffectObjectBase = createGlobalEffect("bubble_effect", size - 1, BubbleEffect);
        obj.location = position;
        IsoEngineProxy.instance.addEffectObject(obj);
        return obj;
    }
	
	public static function playDropAnimation(target:DropItem, onComplete:Function = null):void
	{
		var def:* = dropAnimationDef;
		
		DropUtil.start(target,
					   getRandom(Number(def.vx.@min), Number(def.vx.@max)),
					   getRandom(Number(def.vy.@min), Number(def.vy.@max)),
					   Math.random() >= 0.5 ? 1 : -1,
					   Number(def.gravity.@value),
					   Number(def.bounce.@value),
					   getRandom(Number(def.bottom.@min), Number(def.bottom.@max)),
					   onComplete);
	}
	
	public static function playCollectAnimation(target:DisplayObject, 
												point:Point,
												onComplete:Function = null):TweenMax
	{
		var def:* = collectAnimationDef;
		var easeRef:Class = getDefinitionByName(String(def.ease.@classRef)) as Class;
		
		if (StageProxy.isFullScreenMode)
		{
			point.y += (target.y > point.y ? -1 : 1) * (StageProxy.screenHeight - StageProxy.normalStageHeight) / 2;
		}
		
		LayerManager.collectLayer.addChild(target);
		var tween:TweenMax = TweenMax.to(target, 
										 Number(def.time.@value), 
										 { x:point.x, 
										   y:point.y, 
										   ease: easeRef[String(def.ease.@func)],
										   onComplete:onComplete } );
		return tween;
	}
	
	public static function playCollectFadeOutAnimation(target:DisplayObject, 
													   onComplete:Function = null):TweenMax
	{
		var def:* = collectFadeOutAnimationDef;
		var easeRef:Class = getDefinitionByName(String(def.ease.@classRef)) as Class;
		var tween:TweenMax = TweenMax.to(target, 
										 Number(def.time.@value), 
										 { alpha: Number(def.alpha.@value),
										   delay: Number(def.delay.@value),
										   scaleX: Number(def.scale.@value),
										   scaleY: Number(def.scale.@value),
										   ease: easeRef[String(def.ease.@func)],
										   onComplete:function():void
										   {
											   if (target.parent) target.parent.removeChild(target);
											   if (onComplete != null) onComplete();
										   }} );
		return tween;
	}
	
	public static function clearFilter(target:DisplayObject):void
	{
		target.filters = null;
	}
	
	public static function getRandom(min:Number, max:Number):Number 
	{
		return min + (Math.random() * (max - min));
	}
	
	private static var minAutoCollectTimeout:Number = 8;
	private static var maxAutoCollectTimeout:Number = 10;
	
	public static function get autoCollectTimeout():Number
	{
		return getRandom(minAutoCollectTimeout, maxAutoCollectTimeout);
	}
}
}


